
#include "AAnimateObject.h"
#include "AWorld.h"

CAAnimateObject::CAAnimateObject(void)
{
	_bAnimationDone = false;
	_bFollowCamera = true;
	_mode = AM_CLAMP;
	_duration = 1.0f;
	_actionBoundingBox.origin = CCPointZero;
	_actionBoundingBox.size = CAWorld::getScreenSize();

	_updated = 0;
}

CAAnimateObject::~CAAnimateObject(void)
{
}

void CAAnimateObject::startAnimation(ccTime timeNow, 
									 CASpriteModelPoseModifierKey* pkeys, size_t count, 
									 EAnimationMode mode, float duration)
{
	GUARD_FUNCTION();

	_timeBegin = timeNow;

	_keys.init(count);
	memcpy(_keys.ptr(), pkeys, count * sizeof(CASpriteModelPoseModifierKey));

	if (duration <= 0.0f)
	{
		duration = 1.0f * (0x3ffffff);
	}
	_duration = duration;
	_mode = mode;

	_bAnimationDone = false;
	_onAnimationStart();

	_updated = 0;
}

void CAAnimateObject::updateAnimation(CAICoordinateConverter* pstage, ccTime timeNow)
{
	_updated++;
	_combinedKeyLast = _combinedKey;

	ccTime duration = _duration;

	EAnimationMode mode = _mode;

	//skip time offset
	if (timeNow < _timeBegin)
		return;

	ccTime time = timeNow - _timeBegin;

	switch (mode)
	{
	case AM_LOOP:		//abcabcabc
		time = fmod(time, duration);
		break;
	case AM_CLAMP:		//abc0
		if (time > duration)
		{
			time = duration;
		}
		break;
	case AM_REVERSE:	//abcbabcba
		time = fmod(time, duration + duration);
		if (time > duration)
		{
			//ccTime over = time - duration;
			//time = duration - over;
			time = duration + duration - time;
		}
		break;
	case AM_EXTENDS:	//abccccccc
		if (time > duration)
		{
			time = duration;
		}
		break;
	default:
		_Assert(false);
		break;
	}

	//size_t i;
	CASpriteModelPoseModifierKey lerpKey;

	CCPoint curpos = getPos();
	pstage->game2pixel(curpos, false);
	curpos.x = curpos.x / _actionBoundingBox.size.width;
	curpos.y = curpos.y / _actionBoundingBox.size.height;
	
	CASpriteModelPoseModifierKey::lerp(_keys, time, curpos, lerpKey);

	CCSpriteFrame* pframe = _onAnimateUpdateFrame(timeNow);

	//now lerpKey + gameKey ==> combinedKey
	if (lerpKey.canModify(PM_YARDPOS))
	{
		CCPoint pos;
		pos.x = _actionBoundingBox.origin.x + lerpKey.x * _actionBoundingBox.size.width;
		pos.y = _actionBoundingBox.origin.y + lerpKey.y * _actionBoundingBox.size.height;
		pstage->pixel2game(pos, false); 
		lerpKey.x = pos.x;
		lerpKey.y = pos.y;
		lerpKey.ModifierRemove(PM_YARDPOS);
		lerpKey.ModifierOr(PM_POS);
	}

	if (lerpKey.canModify(PM_YARDSCALE) || lerpKey.canModify(PM_YARDSCALEX) || lerpKey.canModify(PM_YARDSCALEY))
	{
		CCSize sizeWin = _actionBoundingBox.size;
		CCSize sizeFrame = sizeWin;
		if (pframe)
		{
			sizeFrame = pframe->getOriginalSizeInPixels();
			_Assert(sizeFrame.width > 0.0f);
			_Assert(sizeFrame.height > 0.0f);
		}

		CCSize sizeFinal;
		sizeFinal.width = sizeWin.width * lerpKey.scalex;
		sizeFinal.height = sizeWin.height * lerpKey.scaley;
		float sx = sizeFinal.width / sizeFrame.width;
		float sy = sizeFinal.height / sizeFrame.height;
		if (lerpKey.canModify(PM_YARDSCALEX))
		{
			lerpKey.scalex = sx;
			lerpKey.scaley = sx;
		}
		else if (lerpKey.canModify(PM_YARDSCALEY))
		{
			lerpKey.scalex = sy;
			lerpKey.scaley = sy;
		}
		else
		{
			lerpKey.scalex = sx;
			lerpKey.scaley = sy;
		}
		lerpKey.ModifierRemove(PM_YARDSCALE);
		lerpKey.ModifierRemove(PM_YARDSCALEX);
		lerpKey.ModifierRemove(PM_YARDSCALEY);
		lerpKey.ModifierOr(PM_SCALE);
	}

	lerpKey.combine(_gameKey, _combinedKey);
	
	_onAnimateUpdate(time);

	switch (mode)
	{
	case AM_LOOP:		//abcabcabc
	case AM_REVERSE:	//abcbabcba
	case AM_EXTENDS:	//abccccccc
		//do nothing
		break;
	case AM_CLAMP:		//abc0
		if (time >= duration)
		{
			_bAnimationDone = true; //!!! over !!!
			//_bActionToPositionSet = false;
			_onAnimationStop();
		}
		break;
	default:
		_Assert(false);
		break;
	}
}
